/******************************************************************************* 
 * Copyright (c) 2008 xored software, Inc.  
 * 
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution, and is available at 
 * http://www.eclipse.org/legal/epl-v10.html  
 * 
 * Contributors: 
 *     xored software, Inc. - initial API and Implementation (Yuri Strot) 
 *******************************************************************************/
package com.xored.glance.ui.controls;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;

import com.xored.glance.core.ITextBlock;
import com.xored.glance.core.ITextSource;
import com.xored.glance.core.Match;
import com.xored.glance.ui.UIUtils;

/**
 * @author Yuri Strot
 * 
 */
public class StyledTextSource implements ITextSource {

	private StyledText text;
	private StyledTextBlock[] blocks;
	private RangeGroup[] previous;

	public StyledTextSource(StyledText text) {
		this.text = text;
		blocks = new StyledTextBlock[] { new StyledTextBlock() };
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.xored.glance.core.ITextControl#dispose()
	 */
	public void dispose() {
		clearHighlight();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.xored.glance.core.ITextControl#getText()
	 */
	public ITextBlock[] getBlocks() {
		return blocks;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.xored.glance.core.ITextContainer#getFont()
	 */
	public Font getFont() {
		return text.getFont();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.xored.glance.core.ITextControl#select(com.xored.glance.core.IMatch)
	 */
	public void select(final Match match) {
		UIUtils.asyncExec(text, new Runnable() {

			public void run() {
				text.getDisplay().asyncExec(new Runnable() {

					public void run() {
						if (match != null) {
							text.setSelection(match.getOffset(), match
									.getOffset()
									+ match.getLength());
						} else {
							int x = text.getSelection().x;
							text.setSelection(x, x);
						}
					}
				});
			}
		});
	}

	protected void clearHighlight() {
		if (previous != null && previous.length > 0) {
			for (int i = 0; i < previous.length; i++) {
				RangeGroup group = previous[i];
				text.replaceStyleRanges(group.getStart(), group.getEnd()
						- group.getStart(), new StyleRange[0]);
				StyleRange[] ranges = group.getRanges();
				for (StyleRange range : ranges) {
					text.replaceStyleRanges(range.start, range.length,
							new StyleRange[] { range });
				}
			}
		}
		previous = null;
	}

	protected Color getBgHighlight() {
		return text.getDisplay().getSystemColor(SWT.COLOR_YELLOW);
	}

	protected Color getFgHighlight() {
		return text.getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.xored.glance.core.ITextControl#show(com.xored.glance.core.IMatch[])
	 */
	public void show(final Match[] matches) {
		UIUtils.asyncExec(text, new Runnable() {

			public void run() {
				clearHighlight();
				previous = new RangeGroup[matches.length];
				for (int i = 0; i < matches.length; i++) {
					Match match = matches[i];
					int index = match.getOffset();
					int latIndex = index + match.getLength();
					StyleRange[] matchRanges = text.getStyleRanges(index, match
							.getLength());
					List<StyleRange> ranges = new ArrayList<StyleRange>();
					for (StyleRange styleRange : matchRanges) {
						ranges.add(styleRange);
						if (styleRange.length < 0) {
							continue;
						}
						StyleRange newStyleRangerange = new StyleRange(
								styleRange.start, styleRange.length,
								getFgHighlight(), getBgHighlight(),
								styleRange.fontStyle);
						if (styleRange.start - index > 0)
							text.replaceStyleRanges(index, styleRange.start
									- index,
									new StyleRange[] { newStyleRangerange });
						text.replaceStyleRanges(styleRange.start,
								styleRange.length,
								new StyleRange[] { newStyleRangerange });
						index = styleRange.start + styleRange.length;
					}
					if (latIndex - index > 0) {
						StyleRange newStyleRangerange = new StyleRange(index,
								latIndex - index, getFgHighlight(),
								getBgHighlight());
						text.replaceStyleRanges(index, latIndex - index,
								new StyleRange[] { newStyleRangerange });
					}
					previous[i] = new RangeGroup(match.getOffset(), latIndex,
							ranges.toArray(new StyleRange[ranges.size()]));
				}
			}
		});
	}

	private class StyledTextBlock implements ITextBlock {

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.xored.glance.core.ITextBlock#getText()
		 */
		public String getText() {
			final String[] texts = new String[1];
			text.getDisplay().syncExec(new Runnable() {

				public void run() {
					texts[0] = text.getText();
				}
			});
			return texts[0];
		}

	}

}
